import json
import struct

from PyQt6.QtCore import Qt
from PyQt6.QtGui import QColor
from PyQt6.QtWidgets import QGraphicsEllipseItem, QGraphicsLineItem, QGraphicsRectItem, QGraphicsItem, QGraphicsTextItem


def from_item_to_data(item: QGraphicsItem):

    """
    将 Qt6 图形转换为 Python 字典以便记录

    - 通用

      - GType：图元类型，str
      - SPosX：场景 X 坐标，float
      - SPosY：场景 Y 坐标，float
      - Scale：缩放倍率，float
      - Rotation：旋转角度，float
      - ZValue：叠放次序，float

    - 圆、矩形（`QGraphicsEllipseItem`、`QGraphicsRectItem`）

      - Width：宽度，float
      - Height：高度，float
      - PenWidth：线宽，float
      - PenStyle：线型，int(枚举)
      - PenColor：线条颜色，list[int]
      - BrushColor：填充颜色，list[int]

    - 直线（`QGraphicsLineItem`）

      - PenWidth：线宽，float
      - PenStyle：线型，int(枚举)
      - PenColor：线条颜色，list[int]

    - 文字（`QGraphicsTextItem`）

      - Text：文本内容，str
      - Font：字体，str
      - FontSize：字号，int
      - Bold：加粗，bool
      - Italic：斜体，bool
      - TextColor：颜色，list[int]

    :param item: Qt 图形，支持 `QGraphicsEllipseItem`、`QGraphicsRectItem`、`QGraphicsLineItem`、`QGraphicsTextItem`
    :return: 字典记录
    """
    data = create_base_item_data(item)
    if isinstance(item, QGraphicsEllipseItem) or isinstance(item, QGraphicsRectItem):
        # 圆, 矩形
        write_brush(item, data)
        write_size(item, data)
        write_pen(item, data)
    elif isinstance(item, QGraphicsLineItem):
        write_pen(item, data)
    elif isinstance(item, QGraphicsTextItem):
        data['Text'] = item.toPlainText()
        data['TextColor'] = list(item.defaultTextColor().getRgb())
        write_font(item, data)
    return data


def create_base_item_data(graph: QGraphicsItem):
    return {
        'GType': graph.__class__.__name__,
        'SPosX': graph.pos().x(),
        'SPosY': graph.pos().y(),
        'Scale': graph.scale(),
        'Rotation': graph.rotation(),
        'ZValue': graph.zValue()
    }


def write_size(item: QGraphicsItem, data: dict):
    rect = item.boundingRect()
    data['Width'] = rect.width()
    data['Height'] = rect.height()


def write_pen(item: QGraphicsItem, data: dict):
    pen = item.pen()
    data['PenWidth'] = pen.width()
    data['PenStyle'] = pen.style().value
    data['PenColor'] = list(pen.color().getRgb())


def write_brush(item: QGraphicsItem, data: dict):
    brush = item.brush()
    data['BrushColor'] = list(brush.color().getRgb())


def write_font(item: QGraphicsItem, data: dict):
    font = item.font()
    data['Font'] = font.family()
    data['FontSize'] = font.pointSize()
    data['Bold'] = font.bold()
    data['Italic'] = font.italic()


def from_data_to_item(data: dict):
    """
    将图形数据转换为 Qt6 图元对象
    :param data: 数据
    :return: 图元对象
    """
    type = data['GType']
    if type == QGraphicsEllipseItem.__name__:
        item = QGraphicsEllipseItem()
        set_base_item_data(item, data)
        read_size(item, data)
        read_pen(item, data)
        read_brush(item, data)
        return item
    elif type == QGraphicsRectItem.__name__:
        item = QGraphicsRectItem()
        set_base_item_data(item, data)
        read_size(item, data)
        read_pen(item, data)
        read_brush(item, data)
        return item
    elif type == QGraphicsLineItem.__name__:
        item = QGraphicsLineItem()
        set_base_item_data(item, data)
        read_pen(item, data)
        return item
    elif type == QGraphicsTextItem.__name__:
        item = QGraphicsTextItem()
        set_base_item_data(item, data)
        read_font(item, data)
        item.setPlainText(data['Text'])
        item.setDefaultTextColor(read_color(data['TextColor']))
        return item


def read_size(item: QGraphicsItem, data: dict):
    boundingRect = item.boundingRect()
    boundingRect.setWidth(data['Width'])
    boundingRect.setHeight(data['Height'])
    item.setRect(boundingRect)
    return item


def read_pen(item: QGraphicsItem, data: dict):
    pen = item.pen()
    pen.setWidth(data['PenWidth'])
    pen.setStyle(Qt.PenStyle(data['PenStyle']))
    pen.setColor(read_color(data['PenColor']))
    item.setPen(pen)


def read_brush(item: QGraphicsItem, data: dict):
    brush = item.brush()
    brush.setColor(read_color(data['BrushColor']))
    item.setBrush(brush)


def read_color(color: list[int]):
    if len(color) == 3:
        return QColor(color[0], color[1], color[2])
    elif len(color) == 4:
        return QColor(color[0], color[1], color[2], color[3])


def read_font(item: QGraphicsItem, data: dict):
    font = item.font()
    font.setFamily(data['Font'])
    font.setPointSize(data['FontSize'])
    font.setBold(data['Bold'])
    font.setItalic(data['Italic'])
    item.setFont(font)


def set_base_item_data(item: QGraphicsItem, data: dict):
    item.setPos(data['SPosX'], data['SPosY'])
    item.setScale(data['Scale'])
    item.setRotation(data['Rotation'])
    item.setZValue(data['ZValue'])


def save_graph_data(filename, graphs: list[QGraphicsItem]):
    """
    保存图元数据
    :param filename: 保存文件
    :param graphs: 图源对象列表
    """
    # 转换图元对象
    listGraph = [from_item_to_data(item) for item in graphs]
    # 转换为字符串并保存
    boardData = str(listGraph).encode()
    length = len(boardData)
    with open(filename, 'wb+') as f:
        f.write(struct.pack('i', length))
        f.write(boardData)


def load_graph_data(filename):
    """
    从硬盘恢复图元数据
    :param filename: 保存文件
    :return: 图元列表
    """
    with open(filename, 'rb') as f:
        # 读取数据
        length = struct.unpack('i', f.read(4))[0]
        boardData = f.read(length).decode()
        print(boardData)
        boardData = boardData.replace("'", '"').replace(': True', ': true').replace(': False', ': false')
        print(boardData)
        listGraph = json.loads(boardData)
        # 解析数据
        return [from_data_to_item(data) for data in listGraph]
